package com.jeequan.jeepay.core.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

/**
 * http request工具类
 *
 * @author roy
 * @date 2017-12-01
 */
@Slf4j
public class RequestUtils {

    private static final String IP_UNKNOWN = "unknown";

    private static final String IP_LOCAL = "127.0.0.1";

    private static final String IPV6_LOCAL = "0:0:0:0:0:0:0:1";

    /**
     * 静态资源后缀
     */
    private static final String[] staticResourceSuffix = {".html", ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif", ".woff2"};

    /**
     * 根据请求路径判断请求的是否是静态资源
     *
     * @param url
     * @return
     */
    public static boolean isStaticResource(String url) {
        return Arrays.stream(staticResourceSuffix).anyMatch(suffix -> url.endsWith(suffix));
    }

    /**
     * 从线程上下文获取Request请求
     */
    public static HttpServletRequest getHttpRequestFromContext() {
        RequestAttributes attributes = Objects.requireNonNull(RequestContextHolder.getRequestAttributes());
        return ((ServletRequestAttributes) attributes).getRequest();
    }

    /**
     * 获取Request请求参数
     */
    public static Map<String, Object> getQueryParamsFromRequest() {
        HttpServletRequest request = getHttpRequestFromContext();
        Map<String, Object> map = new HashMap<>();
        Enumeration paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = (String) paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length > 0) {
                String paramValue = paramValues[0];
                if (paramValue.length() != 0) {
                    map.put(paramName, paramValue);
                }
            }
        }
        return map;
    }

    /**
     * 从请求中解析出真实的客户端ip地址,无需传参，用于AOP切面
     * HttpServletRequest 对象从线程上下文获取
     *
     * @return
     */
    public static String getIpAddress() {
        HttpServletRequest request = getHttpRequestFromContext();
        return getIpAddress(request);
    }

    /**
     * 从请求中解析出真实的客户端ip地址
     */
    public static String getIpAddress(HttpServletRequest request) {
        // 企图从请求头部获取ip
        String ip = request.getHeader("X-Forwarded-For");
        if (isUnknownIp(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (isUnknownIp(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (isUnknownIp(ip)) {
            ip = request.getRemoteAddr();
        }

        // 根据网卡取本机IP
        if (IP_LOCAL.equals(ip) || IPV6_LOCAL.equals(ip)) {
            try {
                InetAddress inet = InetAddress.getLocalHost();
                ip = inet.getHostAddress();
            } catch (UnknownHostException e) {
                log.error("获取ip地址异常", e);
            }
        }

        // 对于通过代理访问的情况，存在多个ip，多个ip按照','分割，第一个ip为客户端真实ip
        if (StringUtils.isNotBlank(ip) && ip.length() > 15 && ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(","));
        }
        return ip;
    }

    /**
     * 是否未知ip
     *
     * @param ip
     * @return
     */
    private static boolean isUnknownIp(String ip) {
        return StringUtils.isBlank(ip) || IP_UNKNOWN.equalsIgnoreCase(ip);
    }


    /**
     * 获取URL中的?号后的参数，键值对
     *
     * @param request
     * @return
     */
    public static Map<String, String> getParamsFromURL(ServerHttpRequest request) {
        Map<String, String> res = new HashMap();
        MultiValueMap<String, String> temp = request.getQueryParams();
        Iterator<Map.Entry<String, List<String>>> iterator = temp.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, List<String>> next = iterator.next();
            String key = next.getKey();
            String value = next.getValue().get(0);
            res.put(key, value);
        }
        return res;
    }

}
